/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2009 Philippe Durand <draekz@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;

using Anculus.Core;

namespace Galaxium.Protocol.Facebook
{
	public class LoginRequest : AbstractRequest
	{
		public LoginRequest(FBConnection connection) : base (connection)
		{
			
		}
		
		public override void Begin ()
		{
			try
			{
				FBAccount account = (Session.Account as FBAccount);
				
				HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create ("https://login.facebook.com/login.php");
				
				request.Method = "POST";
				request.ContentType = "application/x-www-form-urlencoded";
				request.CookieContainer = new CookieContainer ();
				request.Accept = "*/*";
				request.UserAgent = "Opera/9.50 (Windows NT 5.1; U; en-GB)";
				request.KeepAlive = false;
				request.AllowAutoRedirect = false;
				
				Uri uri = request.RequestUri;
				
				// These cookies are required by the server.
				request.CookieContainer.Add (uri, new Cookie ("isfbe", "false"));
				request.CookieContainer.Add (uri, new Cookie ("test_cookie", "1"));
				
				RequestState state = new RequestState ();
				state.Request = request;
				
				// Create the data we will post to the server.
				state.PostString = string.Format ("email={0}&pass={1}&persistent=1&login=Login&charset_test=%%E2%%AC%%C2%%B4%%E2%%82%%AC%%C2%%B4%%E6%%B0%%B4%%D0%%94%%D0%%84", EncodingUtility.UrlEncode(account.UniqueIdentifier), EncodingUtility.UrlEncode(account.Password));
				state.PostData = Encoding.UTF8.GetBytes (state.PostString);
				request.ContentLength = state.PostData.LongLength;
				
				// Send the "login command" through the connection.
				request.BeginGetRequestStream (BeginLoginRequest, state);
			}
			catch (WebException ex)
			{
				Log.Error (ex, "Exception while requesting login!");
				
				OnFailed (new RequestErrorEventArgs ("Connection Failed!"));
			}
		}
		
		private void BeginLoginRequest(IAsyncResult ar)
		{
			try
			{
				RequestState state = (RequestState)ar.AsyncState;
				HttpWebRequest request = state.Request;
				state.Stream = request.EndGetRequestStream (ar);
				state.Stream.BeginWrite (state.PostData, 0, state.PostData.Length, LoginSent, state);
			}
			catch (Exception ex)
			{
				Log.Error (ex, "Exception while sending login!");
				
				OnFailed (new RequestErrorEventArgs ("Connection Failed!"));
			}
		}
		
		private void LoginSent (IAsyncResult ar)
		{
			try
			{
				RequestState state = (RequestState)ar.AsyncState;
				state.Stream.Close();
				state.Request.BeginGetResponse (ConnectComplete, state.Request);
			}
			catch (Exception ex)
			{
				Log.Error (ex, "Exception while getting login response!");
				
				OnFailed (new RequestErrorEventArgs ("Connection Failed!"));
			}
		}
		
		private void ConnectComplete (IAsyncResult ar)
		{
			try
			{
				HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
				HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);
				Stream stream = response.GetResponseStream ();
				
				string str = String.Empty;
				
				if (response.ContentLength > 0)
				{
					byte[] data = new byte[response.ContentLength];
					int done = 0, read;
					
					while ((read = stream.Read (data, done, (int)Math.Min (data.Length - done, 256))) > 0)
						done += read;
					
					str = Encoding.UTF8.GetString (data);
				}
				
				CookieCollection list = request.CookieContainer.GetCookies (new Uri ("https://login.facebook.com/login.php"));
				bool success = false;
				
				foreach (Cookie cookie in list)
				{
					if (cookie.Name.CompareTo("c_user") == 0)
					{
						(Session.Account as FBAccount).ProfileID = long.Parse(cookie.Value);
						success = true;
					}
					
					_connection.SavedCookies.Add (cookie);
				}
				
				if (!success)
				{
					OnFailed (new RequestErrorEventArgs ("Invalid Credentials!"));
				}
				else
				{
					OnCompleted ();
				}
			}
			catch (Exception ex)
			{
				Log.Error (ex, "Exception while reading login response!");
				
				OnFailed (new RequestErrorEventArgs ("Connection Failed!"));
			}
		}
	}
}
